
//#define DEBUG1
//#define DCF_POLLIN
//#define DCF_CONRAD

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#include "HwAbstraction.h"
#include "lcd.h"
#include "EleAl.h"
#include "menu.h"
#include "TimeDate.h"
#include "Alarm.h"
#include "Globals.h"
#include "LightControl.h"
#include "DCF77.h"
#include "ButtonControl.h"
#include "DisplayControl.h"
#include "SoundControl.h"
#include "uart.h"
#include "TimerControl.h"
#include "Testing.h"
#include "DisplayOutput.h"
#include "ShiftRegControl.h"

typedef struct
{
  uint8_t Sec       :1; /* second */
  uint8_t Sec2      :1; /* second 2 (async) */
  uint8_t Sec3      :1; /* second 3 (async) */
  uint8_t Sec5th    :1; /* fifth of a second */
  uint8_t Sec2nd    :1; /* half of a second */
  uint8_t Min       :1; /* minute */
  uint8_t HeartBeat :1; /* every heartbeat */
} T_Refresh;

#define YEARBASE_U16 ((uint16_t) (2000U))
uint16_t gEleAlCount_u16     = 0;
static T_Refresh gEleAlRefresh_t;

void EleAlSecondIndication( void );
void EleAlMinuteIndication( void );
void EleAlHeartBeatIndication( void );
void EleAlTickGeneration( void );
void EleAlLightControl( uint8_t iButton_u8 );

uint8_t mode = 0;
uint8_t gMenuItem_u8 = 1; // Chosen menu

void ME_time1(void)
{

}

void ME_time2(void)
{
}

int main(void)
{
  DDRD = 0x70;
  DDRB = 0x00;
  DDRC = (1 << DDC4);
  //	PORTC |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3);
  PORTD |= (1 << PD2); // Pull-up for zero-crossing and output for display
  //	flags.sound_mode=1;
  /* Init time and day */
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
  TidInit(); /* uses function pointer */
  TicInit(); /* uses function pointer */
  BcoInit(); /* uses function pointer */
  SrcInit();
  DcfInit();
  MenuInit();
  DispInit();
  ScoInit();
  LcoInit();
  AlaInit();

  TestInit();

  TidRegisterNotification( EleAlSecondIndication, SecondChange );
  TidRegisterNotification( EleAlMinuteIndication, MinuteChange );
  TicRegisterNotification( EleAlHeartBeatIndication );
  BcoRegisterNotification( EleAlLightControl, Button_High2ExtHigh, Button_Cap );
  /* enable interrupts */
  /* Let's go! */
  lcd_clrscr();

  sei();
  uart_puts("EleAl started!\r\n");
  TidGetStoredTimeDate( );
  while (1)
  {
    /* Things to be performed every second */
    if ( 0 != gEleAlRefresh_t.Sec )
    {
      gEleAlRefresh_t.Sec = 0;
      TestCyclic( );
    }
    if( 0 != gEleAlRefresh_t.Sec2 )
    {
      gEleAlRefresh_t.Sec2 = 0;
      AlaCyclic( );
    }
    if( 0 != gEleAlRefresh_t.Sec3 )
    {
      gEleAlRefresh_t.Sec3 = 0;
      MenuCyclic( );
    }
    /* Things to be performed every minute */
    if( 0 != gEleAlRefresh_t.Min )
    {
      gEleAlRefresh_t.Min = 0;
    }
    if( 0 != gEleAlRefresh_t.Sec2nd )
    {
      gEleAlRefresh_t.Sec2nd = 0;
      TidCyclic( );
      SrcCyclic( );
    }
    /* Things to be performed every heartbeat */
    if( 0 != gEleAlRefresh_t.HeartBeat )
    {
      gEleAlRefresh_t.HeartBeat = 0;
      EleAlTickGeneration( );
      BcoCyclic( );
      ScoCyclic( );
    }
#if 0
      if (flags.timer1 && gEleAlCount_u16 == 0)
      {
        /* Update time module */
        //  One second passed  - Everything inside here
        //  what should be done every second
        if (flags.button_touch && flags.button_touch_duration < 255)
        {
          flags.button_touch_duration++;
        }
        else
        {
          flags.button_touch_duration = 0;
        }

        if (flags.button_touch_duration == 2 && mode != MODE_WAKE_UP)
        {
          LcoSetBrightness( BRIGHTNESS_MIN );
          LcoToggleLight();
        }
        // **** ALARM ****


        }

        switch (mode)
        {
          case MODE_CLOCK: // Normal display mode
            // Respond to buttons
            if (flags.button_ok)
            {
              mode = MODE_MENU;
              flags.menu_drawn = 0;
            }

            if (flags.button_back)
              dimmer_on();
            //			if (flags.button_back)
            //				dimmer_off();
            if( flags.button_left )
            {
              LcoDecBrightness();
            }
            if( flags.button_right )
            {
              LcoIncBrightness();
            }

            if (gEleAlSecRefresh_u8)
            {
              T_TimeDate lTimeDate;
              gEleAlSecRefresh_u8 = 0;
              /* Backlight on/off */
              TidGetTimeDate( &lTimeDate );
              /*
               * TODO (11-09-27): correct if necessary
               * itoa(dcf_last_sync, text, 10);
               */
              lcd_gotoxy(0, 0);
              lcd_puts(text);

              lcd_gotoxy(4, 0);
              format_time( (T_Time*) &lTimeDate.Time, text, 0 );
              lcd_puts(text);

              lcd_gotoxy(3, 1);
              format_date( (T_Date*) &lTimeDate.Date, text, 0 );
              lcd_puts(text);

              lcd_gotoxy(13, 0);
              if (DcfGetSyncState())
                lcd_putc(0x00);
              else
                lcd_putc(' ');
              if (flags.alarm)
                lcd_putc(0x01);
              else
                lcd_putc(' ');
              /*				lcd_gotoxy(10, 1);
				 itoa(flags.button_touch, text, 10);
				 lcd_puts(text);
				 lcd_putc(' ');*/
            }
            break;
          case 1:
            // *** Display menu ***
            if (!flags.menu_drawn) {
              display_menu(gMenuItem_u8);
              flags.menu_drawn = 1;
            }

            // Respond to buttons
            if (flags.button_left)
            {
              menu_left();
              display_menu(gMenuItem_u8);
            }
            else if (flags.button_right)
            {
              menu_right();
              display_menu(gMenuItem_u8);
            }
            else if (flags.button_back)
            {
              menu_back();
              if (mode == MODE_MENU)
                display_menu(gMenuItem_u8);
            }
            else if (flags.button_ok)
            {
              menu_ok();
              display_menu(gMenuItem_u8);
            }
            else if (flags.button_back)
            {
              mode = MODE_CLOCK;
              flags.menu_drawn = 0;
            }
            break;
          case MODE_MAXLIGHT:
          {
            char temptext[17];
            if (!flags.menu_drawn)
            {
              lcd_clrscr();
              memcpy_P(&temptext, menu_str13, 17);
              draw_bar(flags.maxlight, temptext);
              flags.menu_drawn = 1;
            }

            if (flags.button_right)
            {
              if (flags.maxlight < 15)
                flags.maxlight++;
              memcpy_P(&temptext, menu_str13, 17);
              draw_bar(flags.maxlight, temptext);
            }
            else if (flags.button_left)
            {
              if (flags.maxlight > 0)
                flags.maxlight--;
              memcpy_P(&temptext, menu_str13, 17);
              draw_bar(flags.maxlight, temptext);
            }
            else if (flags.button_back)
            {
              mode = MODE_MENU;
              flags.menu_drawn = 0;
            }
          }
          break;

          case MODE_SET_ALARM:
          {
            static uint8_t temp_hour;
            static uint8_t temp_minute;
            static uint8_t edit_position;
            char temptext[17];
            if (!flags.menu_drawn)
            {
              // Somewhat incorrect way to read the alarm time
              //            temp_hour = flags.alarm_hour;
              //            temp_minute = flags.alarm_minute;
              edit_position = 0;

              lcd_clrscr();
              memcpy_P(&temptext, menu_str4, 17);
              lcd_puts(temptext);
              flags.menu_drawn = 1;
            }

            if (gEleAlCount_u16 == 0)
            {
              lcd_gotoxy(0, 1);
              itoa(temp_hour, text, 10);
              if (temp_hour < 10)
                lcd_putc('0');
              lcd_puts(text);
              lcd_putc(':');
              itoa(temp_minute, text, 10);
              if (temp_minute < 10)
                lcd_putc('0');
              lcd_puts(text);
            }

            if (gEleAlCount_u16 == 40)
            {
              lcd_gotoxy(0, 1);

              if (!edit_position)
              {
                lcd_puts("__");
              }
              else
              {
                itoa(temp_hour, text, 10);
                if (temp_hour < 10)
                  lcd_putc('0');
                lcd_puts(text);
              }

              lcd_putc(':');
              if (edit_position)
              {
                lcd_puts("__");
              }
              else
              {
                itoa(temp_minute, text, 10);
                if (temp_minute < 10)
                {
                  lcd_putc('0');
                }
                lcd_puts(text);
              }
            }

            if (flags.button_left)
            {
              if (edit_position)
              {
                temp_minute--;
                if (temp_minute > 59)
                  temp_minute = 59;
              }
              else
              {
                temp_hour--;
                if (temp_hour > 23)
                {
                  temp_hour = 23;
                }
              }
            }
            if (flags.button_right)
            {
              if (edit_position)
              {
                temp_minute++;
                if (temp_minute > 59)
                {
                  temp_minute = 0;
                }
              }
              else
              {
                temp_hour++;
                if (temp_hour > 23)
                {
                  temp_hour = 0;
                }
              }
            }
            else if (flags.button_ok)
            {
              edit_position++;
              if (edit_position == 2)
              {
                //              flags.alarm_hour = temp_hour;
                //              flags.alarm_minute = temp_minute;
                /*
                 * TODO (11-09-20): correct this:
                 * calculate_time(flags.alarm_hour, flags.alarm_minute, 5, &flags.alarm_hour_2, &flags.alarm_minute_2);
                 */
                flags.alarm_repeat = 1;
                mode = MODE_MENU;
                flags.menu_drawn = 0;
              }
            }
            else if (flags.button_back)
            {
              mode = MODE_MENU;
              flags.menu_drawn = 0;
            }
          }
          break;
#ifdef	DEBUG1
          case MODE_DEBUG:
          {
            if (debug_1 > 0)
            {
              //				lcd_clrscr();
              //				lcd_gotoxy(0, 0);
              //				itoa(debug_1, text, 10);
              //				lcd_puts(text);
              //				lcd_putc(' ');
              itoa(debug_2, text, 10);
              lcd_puts(text);

              itoa(rx_counter, text, 10);
              lcd_gotoxy(5, 0);
              lcd_puts(text);

              lcd_gotoxy(10 + (rx_counter % 5), 0);
              if (dcf_last_interval > 9)
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }

              lcd_gotoxy(10 + (rx_counter % 5), 1);
              if (dcf_signal & ((unsigned long long) 0x01 << (rx_counter - 1)))
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }

              lcd_gotoxy(0, 1);
              if (flags.parity_P1)
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }
              if (rx_buffer->P1)
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }
              lcd_putc(' ');
              if (flags.parity_P2)
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }
              if (rx_buffer->P2)
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }
              lcd_putc(' ');
              if (flags.parity_P2)
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }
              if (rx_buffer->P3)
              {
                lcd_putc('1');
              }
              else
              {
                lcd_putc('0');
              }
              debug_1 = 0;
            }
            if (flags.button_back)
            {
              mode = MODE_MENU;
              flags.menu_drawn = 0;
            }
          }
          break;
#endif
        }
        flags.timer1 = 0; // Reset timer flag so it can be set again
      }
      // Activate Interrupts
    }
#endif
  }
}

void EleAlSecondIndication( void )
{
  gEleAlRefresh_t.Sec = 1;
}

void EleAlMinuteIndication( void )
{
  gEleAlRefresh_t.Min = 1;
}

void EleAlHeartBeatIndication( void )
{
  gEleAlRefresh_t.HeartBeat = 1;
}

void EleAlTickGeneration( void )
{
  static uint8_t lSecondDivider_u8 = 0;
  static const uint8_t lSecondCount_u8 = 1000/20/*50 ms*/;
  static const uint8_t lDivSec2_u8   = lSecondCount_u8/2;
  static const uint8_t lDivSec3_u8   = lSecondCount_u8/2+lSecondCount_u8/4;
  static const uint8_t lDivSec5th_u8 = lSecondCount_u8/5;
  static const uint8_t lDivSec2nd_u8 = lSecondCount_u8/2;
  ++lSecondDivider_u8;
  if( 0 == lSecondDivider_u8 % lDivSec5th_u8 )
  {
    gEleAlRefresh_t.Sec5th = 1;
  }
  if( 0 == lSecondDivider_u8 % lDivSec2nd_u8 )
  {
    gEleAlRefresh_t.Sec2nd = 1;
  }
  if( lDivSec2_u8 == lSecondDivider_u8 )
  {
    gEleAlRefresh_t.Sec2 = 1;
  }
  if( lDivSec3_u8 == lSecondDivider_u8 )
  {
    gEleAlRefresh_t.Sec3 = 1;
  }
  if( lSecondCount_u8 == lSecondDivider_u8 )
  {
    lSecondDivider_u8 = 0;
  }
}

void EleAlLightControl( uint8_t iButton_u8 )
{
  static T_Bool lLightOn_t = FALSE;
  if( TRUE != lLightOn_t )
  {
    lLightOn_t = TRUE;
    LcoSetBrightness( 100 );
    LcoSetLight( LightOn );
    UART_PUT_STR("Light on");
  }
  else
  {
    lLightOn_t = FALSE;
    LcoSetBrightness( 0 );
    LcoSetLight( LightOff );
    UART_PUT_STR("Light off");
  }

}
